package xyz.thoughtset.viewer.ai.mcp.client.factory;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.ai.tool.support.ToolUtils;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import xyz.thoughtset.viewer.ai.mcp.client.entity.McpBotInfo;
import xyz.thoughtset.viewer.ai.mcp.client.entity.McpClientLink;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;


@Component
public class McpBotFactory implements DisposableBean {

    private final Map<String, McpClientLink> MCP_CLIENT_MAP = new ConcurrentHashMap<>();
    @Autowired
    private ObjectMapper objectMapper;

    public void createMcpServer(List<McpBotInfo> list) {
        if (list == null || list.isEmpty()) return;
        for (McpBotInfo ele : list) {
            createMcpServer(ele);
        }
    }

    public McpClientLink createMcpServer(McpBotInfo clientInfo) {
        McpClientLink link = clientInfo.buildClientLink(objectMapper);
        MCP_CLIENT_MAP.put(clientInfo.getId(), link);
        return link;
    }

    @Override
    public void destroy() throws Exception {
        MCP_CLIENT_MAP.values().parallelStream().forEach(McpClientLink::close);
    }

    public ToolCallback[] clientsTools(List<String> serverIds) {
        var array = serverIds.parallelStream()
                .map(this::findAndCheck)
                .flatMap(mcpLink -> mcpLink.mcpTools()
                        .stream()
                        .filter(tool -> mcpLink.defaultToolFilter().test(mcpLink.mcpBotInfo(), tool))
                        .map(tool -> new McpToolCallback(mcpLink, tool))
                )
                .toArray(ToolCallback[]::new);
        validateToolCallbacks(array);
        return array;
    }


    public List<String> clientsToolNames(String serverId) {
        McpClientLink link = findAndCheck(serverId);
        List<String> toolNames = link.mcpTools().stream()
                .map(tool -> tool.name())
                .collect(Collectors.toList());
        return toolNames;
    }
    public List clientTools(String serverId) {
        McpClientLink link = findAndCheck(serverId);
        return link.mcpTools();
    }

    private void validateToolCallbacks(ToolCallback[] toolCallbacks) {
        List<String> duplicateToolNames = ToolUtils.getDuplicateToolNames(toolCallbacks);
        if (!duplicateToolNames.isEmpty()) {
            throw new IllegalStateException(
                    "Multiple tools with the same name (%s)".formatted(String.join(", ", duplicateToolNames)));
        }
    }

    public void removeClient(String serverId) {
        if (!StringUtils.hasText(serverId) ||!MCP_CLIENT_MAP.containsKey(serverId)) {
            return;
        }
        McpClientLink link = MCP_CLIENT_MAP.remove(serverId);
        if (link != null) {
            link.close();
        }
    }

    //todo :临时处理sse断联问题
    private McpClientLink findAndCheck(String serverId){
        McpClientLink link = MCP_CLIENT_MAP.get(serverId);
        try {
            link.testLink();
        }catch (Exception e){
            link = createMcpServer(link.mcpBotInfo());
        }
        return link;
    }


}
